package com.chen.blue.aop;

import cn.hutool.core.date.DateUtil;

import com.chen.blue.dictionary.CommonDict;
import com.chen.blue.domain.dto.system.LogDto;
import com.chen.blue.service.manager.AsyncManager;
import com.chen.blue.service.manager.factory.AsyncFactory;
import com.chen.blue.service.security.SecurityService;
import com.chen.blue.service.system.ILogService;
import com.chen.blue.sysconfig.SystemConfig;
import com.chen.blue.utils.ip.IpUtils;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.*;
import org.springframework.core.NamedThreadLocal;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.util.Date;
import java.util.Objects;


/**
 * Created By CLT On 2023/10/29.
 */
@SuppressWarnings("all")
@Aspect
@Slf4j
@Component
public class LogAspect {

    @Resource
    private ILogService logService;

    @Resource
    private SystemConfig systemConfig;

    /**
     * 执行顺序
     * 1.around
     * 2.before
     * 3.afterReturn/afterThrow
     * 4.after
     * 5.around
     */

    ThreadLocal<Long> COST_TIME = new NamedThreadLocal<Long>("Cost_Time");

    @Before(value = "@annotation(apiOperation)")
    public void doBefore(JoinPoint point, ApiOperation apiOperation) {
        COST_TIME.set(System.currentTimeMillis());
    }

    @AfterReturning("@annotation(apiOperation)")
    public void doAfterReturn(JoinPoint point, ApiOperation apiOperation) {
        handleLog(point, apiOperation, null);
    }

    @AfterThrowing(pointcut = "@annotation(apiOperation)", throwing = "e")
    public void doAfterThrow(JoinPoint point, ApiOperation apiOperation, Exception e) {
        handleLog(point, apiOperation, e);
    }

    protected void handleLog(JoinPoint point, ApiOperation apiOperation, Exception e) {

        if (systemConfig.isLogEnabled()) {

            try {
                LogDto logDto = new LogDto();
                // 操作的方法
                Signature method = point.getSignature();
                // 操作的模块
                Object target = point.getTarget();
                Api annotation = target.getClass().getAnnotation(Api.class);
                String system = annotation.tags()[0];
                // 操作的时间
                String date = DateUtil.format(new Date(), "yyyy-MM-dd HH:mm:ss");
                // 操作人员
                String currentName = SecurityService.currentUserName();
                // 操作类型
                String type = apiOperation.value();

                logDto.setLogOptionName(method.getName());
                logDto.setLogOptionPerson(currentName.toString());
                logDto.setLogSystem(system);
                logDto.setLogOptionDate(DateUtil.parse(date, "yyyy-MM-dd HH:mm:ss"));
                logDto.setLogOptionStatus(CommonDict.OPTION_SUCCESS);
                logDto.setLogOptionTime(System.currentTimeMillis() - COST_TIME.get());
                logDto.setLogOptionAddressIp(IpUtils.getIpAddr());
                logDto.setLogOptionType(type);

                if (Objects.nonNull(e)) {
                    logDto.setLogOptionStatus(CommonDict.OPTION_FAILD);
                }

                logDto.setCreator(SecurityService.currentUserName());

                // 异步记录日志
                AsyncManager.me().execute(AsyncFactory.recordOper(logDto));

            } catch (Exception ex) {
                log.error(ex.getMessage());
            } finally {
                COST_TIME.remove();
            }
        }

    }


}
